package services

import (
	"TaskAssignmentSystem/internal/admin/dao"
	"TaskAssignmentSystem/internal/pkg/modelbase"
	"TaskAssignmentSystem/pkg/db/mysql"
	"TaskAssignmentSystem/pkg/db/redis"
	"TaskAssignmentSystem/pkg/timehandler"
	"TaskAssignmentSystem/pkg/utils"
	"fmt"
	jsoniter "github.com/json-iterator/go"
	"gorm.io/gorm"
	"time"
)

type ProjectService struct {
}

func (p *ProjectService) ById(id uint) (dao.SystemProject, error) {
	var projectDao dao.Common[dao.SystemProject]
	return projectDao.First(map[string]interface{}{"id": id})
}

func (p *ProjectService) ByIdUpdateVisibility(projectId string, visibility uint) error {
	var projectDao dao.Common[dao.SystemProject]
	projectDao.Query = map[string]interface{}{"project_id": projectId}
	return projectDao.Update(map[string]interface{}{"visibility": visibility}).Error
}

func (p *ProjectService) ByIdUpdateNewUserRestrtction(projectId string, newUserRestrtction uint) error {
	var projectDao dao.Common[dao.SystemProject]
	projectDao.Query = map[string]interface{}{"project_id": projectId}
	return projectDao.Update(map[string]interface{}{"new_user_restrtction": newUserRestrtction}).Error
}

func (p *ProjectService) ByIdUpdateOldUserRestrtction(projectId string, oldUserRestrtction uint) error {
	var projectDao dao.Common[dao.SystemProject]
	projectDao.Query = map[string]interface{}{"project_id": projectId}
	if res, err := projectDao.First(projectDao.Query); err != nil {
		return err
	} else {
		var userRestrictionDao dao.Common[dao.SystemUserRestriction]
		userRestrictionDao.DeleteByStringColumn("project_id", res.ProjectId)
		if oldUserRestrtction == 1 {
			bathInsetSql := "insert into tas_system_user_restriction (created_at,updated_at,system_user_id,project_id,lower_limit,`limit`,cd,day_limit,day_give_up_limit)" +
				fmt.Sprintf(" select NOW(),NOW(),id,'%s',%d,%d,%d,%d,%d from tas_system_user where user_id is NOT null", res.ProjectId, res.LowerLimit, res.Limit, res.Cd, res.DayLimit, res.DayGiveUpLimit)
			projectDao.ExecSql(bathInsetSql)
		}
		return projectDao.Update(map[string]interface{}{"old_user_restrtction": oldUserRestrtction}).Error
	}
}

func (p *ProjectService) RemoveById(id uint) error {

	_db := mysql.GetDB()
	err := _db.Transaction(func(tx *gorm.DB) error {
		var projectServe CommonService[dao.SystemProject]
		projectServe.Query = map[string]interface{}{"id": id}
		projectServe.Tx = tx
		var project dao.SystemProject
		if err := tx.Model(dao.SystemProject{}).Where(map[string]interface{}{"id": id}).First(&project).Error; err != nil {
			return err
		}

		//如果删除的是一审项目,则把对应的答主项目关联的一审项目改为空
		if project.EnumType == modelbase.AuditProj {
			if err := tx.Model(dao.SystemProject{}).Where("project_id = ?", project.WorkProjectId).Update("audit_project_id", "").Error; err != nil {
				return err
			}
		} else if project.EnumType == modelbase.FinalProj {
			//如果删除的是二审项目,则把对应的答主项目关联的二审项目改为空
			if err := tx.Model(dao.SystemProject{}).Where("project_id = ?", project.WorkProjectId).Update("final_project_id", "").Error; err != nil {
				return err
			}
		}

		if err := projectServe.RemoveUnscoped(); err != nil {
			return err
		}

		var common dao.Common[dao.SystemTopic]
		common.Tx = tx
		common.Query = map[string]interface{}{"project_id": project.ProjectId}

		if err := tx.Model(&dao.TopicNote{}).Unscoped().Where("system_topic_id IN (?)", tx.Model(&dao.SystemTopic{}).Where(common.Query).Select("Id")).Delete(&dao.TopicNote{}).Error; err != nil {
			return err
		}
		if err := tx.Model(&dao.TopicConfiguration{}).Unscoped().Where("system_topic_id IN (?)", tx.Model(&dao.SystemTopic{}).Where(common.Query).Select("Id")).Delete(&dao.TopicConfiguration{}).Error; err != nil {
			return err
		}
		var topics []struct {
			Id uint
		}
		var ids []uint
		tx.Model(&dao.SystemTopic{}).Where(map[string]interface{}{"project_id": project.ProjectId}).Select("Id").Find(&topics)
		var topicAnswerServe TopicAnswerService
		topicAnswerServe.Tx = tx
		for _, i2 := range topics {
			ids = append(ids, i2.Id)
		}
		if err := topicAnswerServe.DeleteTopicAnswerData2(ids); err != nil {
			return err
		}
		if err := tx.Model(&dao.TopicUserRecord{}).Unscoped().Where("system_topic_id IN (?)", tx.Model(&dao.SystemTopic{}).Where(common.Query).Select("Id")).Delete(&dao.TopicUserRecord{}).Error; err != nil {
			return err
		}
		if err := common.RemoveUnscopedPreload(map[string]interface{}{"project_id": project.ProjectId}).Error; err != nil {
			return err
		}
		return nil
	})
	return err
}

// InsertExcel 通过 Excel 导入项目表
func (p *ProjectService) InsertExcel(projectId string, projectObj dao.SystemProject) error {
	_db := mysql.GetDB()
	//判断导入截止时间处理项目状态
	if projectObj.OfflineDateTime.Before(time.Now().In(utils.LocationZone)) {
		projectObj.Status = 2
	} else {
		if projectObj.OnlineDateTime.Before(time.Now().In(utils.LocationZone)) {
			projectObj.Status = 1
		}
	}
	return _db.Transaction(func(tx *gorm.DB) error {
		//处理定时任务
		err := tx.Model(&dao.SystemProject{}).Create(&projectObj).Error
		if err != nil {
			return err
		}
		if time.Now().In(utils.LocationZone).Before(projectObj.OnlineDateTime.In(utils.LocationZone)) {
			if projectObj.OnlineDateTime.Format(timehandler.FormatLayoutDate) == time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutDate) {
				//执行时间在当日，创建redis 过期事件
				expiration := projectObj.OnlineDateTime.Unix() - time.Now().In(utils.LocationZone).Unix()
				key := fmt.Sprintf("task_project@%d_%s", projectObj.Id, "10")
				value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 10, "status": 1})
				if setNX := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); setNX != nil {
					return setNX
				}
			} else {
				//创建一个倒计时任务
				var task dao.SystemTask
				task.TaskType = 10
				task.SystemTopicId = projectObj.Id
				task.ExecutionDateTime = projectObj.OnlineDateTime
				task.ExecutionData = map[string]interface{}{"task_type": 10, "status": 1}
				if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
					return err
				}
			}
		}
		if projectObj.OfflineDateTime.In(utils.LocationZone).After(time.Now().In(utils.LocationZone)) {
			if projectObj.OfflineDateTime.Format(timehandler.FormatLayoutDate) == time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutDate) {
				//执行时间在当日，创建redis 过期事件
				expiration := projectObj.OfflineDateTime.Unix() - time.Now().In(utils.LocationZone).Unix()
				key := fmt.Sprintf("task_project@%d_%s", projectObj.Id, "11")
				value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 11, "status": 1})
				if setNX := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); setNX != nil {
					return setNX
				}
			} else {
				//创建一个倒计时任务
				var task dao.SystemTask
				task.TaskType = 11
				task.SystemTopicId = projectObj.Id
				task.ExecutionDateTime = projectObj.OfflineDateTime
				task.ExecutionData = map[string]interface{}{"task_type": 11, "status": 2}
				if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
					return err
				}
			}

		}
		// 查询普通项目
		projectDO := dao.SystemProject{}
		if err := tx.Where("project_id = ?", projectId).First(&projectDO).Error; err != nil {
			return err
		}
		// 导入类型为一审项目
		if projectObj.EnumType == modelbase.AuditProj {
			// 普通关联一审
			if err := tx.Model(dao.SystemProject{}).Where("project_id = ?", projectId).Update("audit_project_id", projectObj.ProjectId).Error; err != nil {
				return err
			}
		}
		// 导入类型为二审项目
		if projectObj.EnumType == modelbase.FinalProj {
			// 普通关联二审
			if err := tx.Model(dao.SystemProject{}).Where("project_id = ?", projectId).Update("final_project_id", projectObj.ProjectId).Error; err != nil {
				return err
			}
			// 一审关联二审
			if err := tx.Model(dao.SystemProject{}).Where("project_id = ?", projectDO.AuditProjectId).Update("final_project_id", projectObj.ProjectId).Error; err != nil {
				return err
			}
			// 二审关联一审
			if err := tx.Model(dao.SystemProject{}).Where("project_id = ?", projectObj.ProjectId).Update("audit_project_id", projectDO.AuditProjectId).Error; err != nil {
				return err
			}
		}
		return nil
	})
}

func (p *ProjectService) BatchUpdateWithWhereForObj(projectId string, projectObj dao.SystemProject) error {
	_db := mysql.GetDB()
	//判断导入截止时间处理项目状态
	if projectObj.OfflineDateTime.Before(time.Now().In(utils.LocationZone)) {
		projectObj.Status = 2
	} else {
		if projectObj.OnlineDateTime.Before(time.Now().In(utils.LocationZone)) {
			projectObj.Status = 1
		}
	}
	return _db.Transaction(func(tx *gorm.DB) error {
		//处理定时任务
		err := tx.Model(&dao.SystemProject{}).Where(map[string]interface{}{"project_id": projectId}).Updates(&projectObj).Error
		if err != nil {
			return err
		}
		if time.Now().In(utils.LocationZone).Before(projectObj.OnlineDateTime.In(utils.LocationZone)) {
			if projectObj.OnlineDateTime.Format(timehandler.FormatLayoutDate) == time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutDate) {
				//执行时间在当日，创建redis 过期事件
				expiration := projectObj.OnlineDateTime.Unix() - time.Now().In(utils.LocationZone).Unix()
				key := fmt.Sprintf("task_project@%d_%s", projectObj.Id, "10")
				value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 10, "status": 1})
				if setNX := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); setNX != nil {
					return setNX
				}
			} else {
				//创建一个倒计时任务
				var task dao.SystemTask
				task.TaskType = 10
				task.SystemTopicId = projectObj.Id
				task.ExecutionDateTime = projectObj.OnlineDateTime
				task.ExecutionData = map[string]interface{}{"task_type": 10, "status": 1}
				if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
					return err
				}
			}
		}
		if projectObj.OfflineDateTime.In(utils.LocationZone).After(time.Now().In(utils.LocationZone)) {
			if projectObj.OfflineDateTime.Format(timehandler.FormatLayoutDate) == time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutDate) {
				//执行时间在当日，创建redis 过期事件
				expiration := projectObj.OfflineDateTime.Unix() - time.Now().In(utils.LocationZone).Unix()
				key := fmt.Sprintf("task_project@%d_%s", projectObj.Id, "11")
				value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 11, "status": 1})
				if setNX := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); setNX != nil {
					return setNX
				}
			} else {
				//创建一个倒计时任务
				var task dao.SystemTask
				task.TaskType = 11
				task.SystemTopicId = projectObj.Id
				task.ExecutionDateTime = projectObj.OfflineDateTime
				task.ExecutionData = map[string]interface{}{"task_type": 11, "status": 2}
				result := tx.Model(&dao.SystemTask{}).First(map[string]interface{}{"task_type": task.TaskType, "system_topic_id": task.SystemTopicId, "execution_date_time": task.ExecutionDateTime})
				if result.RowsAffected == 0 {
					if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
						return err
					}
				}
			}

		}
		if projectObj.EnumType == modelbase.WorkProj {
			return nil
		}
		// 查询普通项目
		projectDO := dao.SystemProject{}
		if err := tx.Where("project_id = ?", projectId).First(&projectDO).Error; err != nil {
			return err
		}
		// 导入类型为一审项目
		if projectObj.EnumType == modelbase.AuditProj {
			// 普通关联一审
			if err := tx.Model(dao.SystemProject{}).Where("project_id = ?", projectDO.WorkProjectId).Update("audit_project_id", projectObj.ProjectId).Error; err != nil {
				return err
			}
		}
		// 导入类型为二审项目
		if projectObj.EnumType == modelbase.FinalProj {
			// 普通关联二审
			if err := tx.Model(dao.SystemProject{}).Where("project_id = ?", projectDO.WorkProjectId).Update("final_project_id", projectObj.ProjectId).Error; err != nil {
				return err
			}
			// 一审关联二审
			if err := tx.Model(dao.SystemProject{}).Where("project_id = ?", projectDO.AuditProjectId).Update("final_project_id", projectObj.ProjectId).Error; err != nil {
				return err
			}
			/*// 二审关联一审
			if err := tx.Model(dao.SystemProject{}).Where("project_id = ?", projectObj.ProjectId).Update("audit_project_id", projectDO.AuditProjectId).Error; err != nil {
				return err
			}*/
		}
		return nil
	})
}

func (p *ProjectService) UpdateProjectStatus(projectId uint, status int) error {
	var projectDao dao.Common[dao.SystemProject]
	return projectDao.UpdateOne(projectId, map[string]interface{}{"status": status}).Error
}
